﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Runtime.Serialization;
using System.Collections.Generic;
using Microsoft.Devices;
using System.IO.IsolatedStorage;
using System.IO;
using Push.EventArguments;

namespace Push.Entities
{
    [DataContractAttribute]
    public class GameManager
    {
        public List<Disc> FirstPlayerDiscs = new List<Disc>();
        private int FirstPlayerCurrentDiscIndex = 0;
        public Disc FirstPlayerCurrentDisc;
        public List<Disc> SecondPlayerDiscs = new List<Disc>();
        private int SecondPlayerCurrentDiscIndex = 0;
        public Disc SecondPlayerCurrentDisc;

        public static int DiscsCount = 5;

        [DataMemberAttribute]
        public bool IsPaused { get; set; }

        public GameState gameState { get; set; }

        [DataMemberAttribute]
        public long CurrentGameTime;

        [DataMemberAttribute]
        public long ProcessedGameTime;

        [DataMemberAttribute]
        public long LastTickCount;

        static Random rand = new Random();

        public static VibrateController vibrate = VibrateController.Default;

        public const double RinkWidth = TotalWidth;
        public const double RinkHeight = 550;
        public const double TotalHeight = 800;
        public const double TotalWidth = 480;

        public const double DiscTopOffset = 62.5;

        private const double dT = 0.016;

        public delegate void DiscAddedEventHandler(object sender, DiscAddedEventArgs e);
        public event DiscAddedEventHandler DiscAdded;

        public delegate void NextTurnChangedEventHandler(object sender, EventArgs e);
        public event NextTurnChangedEventHandler NextTurn;

        //[DataMemberAttribute]
        //public GameState gameState;
        //[DataMemberAttribute]
        //public PlayerColor ActivePlayer = PlayerColor.Yellow;

        public GameManager()
        {
            gameState = GameState.Pause;
        }

        public void Update()
        {
            if (gameState == GameState.Play && !IsPaused)
            {
                //double dT = (DateTime.Now.Ticks - LastTickCount) / 10000000.0;

                CurrentGameTime += DateTime.Now.Ticks - LastTickCount;

                LastTickCount = DateTime.Now.Ticks;

                while (ProcessedGameTime < CurrentGameTime)
                {
                    ProcessedGameTime += TimeSpan.FromSeconds(dT).Ticks;

                    foreach (Disc disc in FirstPlayerDiscs)
                    {
                        if (disc.discEntity.State == DiscState.InGame)
                        {
                            disc.discEntity.Update(dT);

                            disc.discEntity.CheckPosition();
                        }
                    }

                    foreach (Disc disc in SecondPlayerDiscs)
                    {
                        if (disc.discEntity.State == DiscState.InGame)
                        {
                            disc.discEntity.Update(dT);

                            disc.discEntity.CheckPosition();
                        }
                    }
                }

                ProcessCollisions();

                bool EndRound = true;

                foreach (Disc disc in FirstPlayerDiscs)
                {
                    if (!disc.discEntity.IsStatic && disc.discEntity.State == DiscState.InGame)
                    {
                        EndRound = false;
                        break;
                    }
                }

                if (EndRound)
                {
                    gameState = GameState.Pause;

                    if (NextTurn != null)
                        NextTurn(this, EventArgs.Empty);

                    DiscToStart();
                }
            }
        }

        private void ProcessCollisions()
        {
            for (int i = 0; i < FirstPlayerDiscs.Count - 1; i++)
            {
                for (int j = i + 1; j < FirstPlayerDiscs.Count; j++)
                {
                    if ((!FirstPlayerDiscs[i].discEntity.IsStatic || !FirstPlayerDiscs[j].discEntity.IsStatic) && FirstPlayerDiscs[i].discEntity.State == DiscState.InGame && FirstPlayerDiscs[j].discEntity.State == DiscState.InGame)
                    {
                        double Impulse = FirstPlayerDiscs[i].discEntity.CheckCollision(FirstPlayerDiscs[j].discEntity);

                        if (Impulse > 0.0)
                        {
                            vibrate.Start(TimeSpan.FromMilliseconds(Math.Max(Math.Min(Impulse / 5, 50), 20)));
                        }
                    }
                }
            }

            for (int i = 0; i < SecondPlayerDiscs.Count - 1; i++)
            {
                for (int j = i + 1; j < SecondPlayerDiscs.Count; j++)
                {
                    if ((!SecondPlayerDiscs[i].discEntity.IsStatic || !SecondPlayerDiscs[j].discEntity.IsStatic) && SecondPlayerDiscs[i].discEntity.State == DiscState.InGame && SecondPlayerDiscs[j].discEntity.State == DiscState.InGame)
                    {
                        double Impulse = SecondPlayerDiscs[i].discEntity.CheckCollision(SecondPlayerDiscs[j].discEntity);

                        if (Impulse > 0.0)
                        {
                            vibrate.Start(TimeSpan.FromMilliseconds(Math.Max(Math.Min(Impulse / 5, 50), 20)));
                        }
                    }
                }
            }

            for (int i = 0; i < FirstPlayerDiscs.Count; i++)
            {
                for (int j = 0; j < SecondPlayerDiscs.Count; j++)
                {
                    if ((!FirstPlayerDiscs[i].discEntity.IsStatic || !SecondPlayerDiscs[j].discEntity.IsStatic) && FirstPlayerDiscs[i].discEntity.State == DiscState.InGame && SecondPlayerDiscs[j].discEntity.State == DiscState.InGame)
                    {
                        double Impulse = FirstPlayerDiscs[i].discEntity.CheckCollision(SecondPlayerDiscs[j].discEntity);

                        if (Impulse > 0.0)
                        {
                            vibrate.Start(TimeSpan.FromMilliseconds(Math.Max(Math.Min(Impulse / 5, 50), 20)));
                        }
                    }
                }
            }
        }

        public void GenerateDiscs(int n, bool CreateEntity)
        {
            if (CreateEntity)
            {
                //Stones.Clear();

                

                for (int i = 0; i < n; i++)
                {
                    int size = rand.Next(DiscEntity.MinimumSize, DiscEntity.MaximumSize);

                    Disc disc;

                    //if (i % 2 == 0)
                    //{
                        disc = new Disc(DiscColor.Red, size, i, CreateEntity);
                    //}
                    //else
                    //{
                        

                        //size = rand.Next(DiscEntity.MinimumSize, DiscEntity.MaximumSize);
                    //}

                    disc.ChangeState(DiscState.Waited);

                    if (DiscAdded != null)
                        DiscAdded(this, new DiscAddedEventArgs() { disc = disc });

                    FirstPlayerDiscs.Add(disc);

                    disc = new Disc(DiscColor.Yellow, size, i, CreateEntity);

                    disc.ChangeState(DiscState.Waited);

                    if (DiscAdded != null)
                        DiscAdded(this, new DiscAddedEventArgs() { disc = disc });

                    SecondPlayerDiscs.Add(disc);
                }
            }
            else
            {
                for (int i = 0; i < n; i++)
                {
                    //if (i % 2 == 0)
                    //{
                        FirstPlayerDiscs[i].ChangeColor(DiscColor.Red);                        
                    //}
                    //else
                    //{
                        SecondPlayerDiscs[i].ChangeColor(DiscColor.Yellow);
                    //}

                        FirstPlayerDiscs[i].ChangeRadius(rand.Next(DiscEntity.MinimumSize, DiscEntity.MaximumSize));
                        SecondPlayerDiscs[i].ChangeRadius(rand.Next(DiscEntity.MinimumSize, DiscEntity.MaximumSize));
                }
            }

            DiscsToStartPositions();
        }

        private void DiscsToStartPositions()
        {
            double firstPlayerTotal = 0.0;
            double secondPlayerTotal = 0.0;

            double sideOffset = 24.0;
            double discOffset = 6;

            for (int i = 0; i < DiscsCount; i++)
            {
                int n = DiscsCount;
                //if (i % 2 == 0)
                //{
                    firstPlayerTotal += FirstPlayerDiscs[i].discEntity.Radius;

                    FirstPlayerDiscs[i].discEntity.X = sideOffset + firstPlayerTotal;
                    FirstPlayerDiscs[i].discEntity.Y = DiscTopOffset;

                    firstPlayerTotal += FirstPlayerDiscs[i].discEntity.Radius + discOffset;
                    FirstPlayerDiscs[i].discEntity.Rotation = 0.0;
                    FirstPlayerDiscs[i].discEntity.State = DiscState.Waited;

                    FirstPlayerDiscs[i].discEntity.DistanceToTarget = double.MaxValue;
                //}
                //else
                //{
                    secondPlayerTotal += SecondPlayerDiscs[n - i - 1].discEntity.Radius;

                    SecondPlayerDiscs[n - i - 1].discEntity.X = GameManager.TotalWidth - sideOffset - secondPlayerTotal;
                    SecondPlayerDiscs[n - i - 1].discEntity.Y = GameManager.TotalHeight - DiscTopOffset;

                    secondPlayerTotal += SecondPlayerDiscs[n - i - 1].discEntity.Radius + discOffset;
                    SecondPlayerDiscs[n - i - 1].discEntity.Rotation = 0.0;
                    SecondPlayerDiscs[n - i - 1].discEntity.State = DiscState.Waited;
                //}
                    SecondPlayerDiscs[i].discEntity.DistanceToTarget = double.MaxValue;
            }
        }

        public void DiscToStart()
        {
            FirstPlayerCurrentDisc = null;
            SecondPlayerCurrentDisc = null;

            if (FirstPlayerCurrentDiscIndex < FirstPlayerDiscs.Count)
            {
                FirstPlayerCurrentDisc = FirstPlayerDiscs[FirstPlayerDiscs.Count - FirstPlayerCurrentDiscIndex - 1];
                FirstPlayerCurrentDiscIndex++;
                FirstPlayerCurrentDisc.ChangeState(DiscState.InGame);
                FirstPlayerCurrentDisc.discEntity.X = GameManager.RinkWidth / 2;
                FirstPlayerCurrentDisc.discEntity.Y = DiscTopOffset;
            }

            if (SecondPlayerCurrentDiscIndex < SecondPlayerDiscs.Count)
            {
                SecondPlayerCurrentDisc = SecondPlayerDiscs[SecondPlayerDiscs.Count - SecondPlayerCurrentDiscIndex - 1];
                SecondPlayerCurrentDiscIndex++;
                SecondPlayerCurrentDisc.ChangeState(DiscState.InGame);
                SecondPlayerCurrentDisc.discEntity.X = GameManager.RinkWidth / 2;
                SecondPlayerCurrentDisc.discEntity.Y = GameManager.TotalHeight - DiscTopOffset;
            }
        }

        public void NewGame()
        {
        }

        public int GetRoundResult()
        {
            double Player1MinLength = double.MaxValue;
            double Player2MinLength = double.MaxValue;

            //for (int i = 0; i < Discs.Count; i++)
            //{
            //    if (Discs[i].discEntity.discColor == DiscColor.Yellow)
            //    {
            //        Player1MinLength = Math.Min(Player1MinLength, Discs[i].discEntity.DistanceToTarget);
            //    }

            //    if (Discs[i].discEntity.discColor == DiscColor.Red)
            //    {
            //        Player2MinLength = Math.Min(Player2MinLength, Discs[i].discEntity.DistanceToTarget);
            //    }
            //}

            int Points = 0;

            //for (int i = 0; i < Discs.Count; i++)
            //{
            //    if (Discs[i].discEntity.DistanceToTarget < Math.Max(Player1MinLength, Player2MinLength))
            //    {
            //        Points++;
            //    }
            //}

            return Points * ((Player1MinLength < Player2MinLength) ? 1 : -1);
        }

        public void PushDisc(int Direction, int Velocity)
        {
            FirstPlayerCurrentDisc.discEntity.VelocityY = Velocity * Math.Cos(Direction / 180.0 * Math.PI);
            FirstPlayerCurrentDisc.discEntity.VelocityX = Velocity * Math.Sin(Direction / 180.0 * Math.PI);

            //DeliveryStone.stoneEntity.Friction = StoneEntity.FrictionWithPlayer;
            //DeliveryStone.stoneEntity.VelocityY = InitialPushVelocity * Math.Cos(DeliveryStone.stoneEntity.Rotation / 180.0 * Math.PI);
            //DeliveryStone.stoneEntity.VelocityX = InitialPushVelocity * Math.Sin(DeliveryStone.stoneEntity.Rotation / 180.0 * Math.PI);
            //DeliveryStone.stoneEntity.IsProceed = false;

            //DeliveryStone.stoneEntity.State = StoneState.OnRink;

            gameState = GameState.Play;

            CurrentGameTime = 0;
            ProcessedGameTime = 0;

            LastTickCount = DateTime.Now.Ticks;
        }

        #region Serialization

        public void Save()
        {
            using (IsolatedStorageFile Store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!Store.DirectoryExists("GameManager"))
                {
                    Store.CreateDirectory("GameManager");
                }

                string Path = "\\GameManager\\GameManager.xml";

                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(Path, FileMode.Create, Store))
                {
                    DataContractSerializer dtaContractSerializer = new DataContractSerializer(typeof(GameManager));
                    dtaContractSerializer.WriteObject(stream, this);
                }
            }
        }

        public static GameManager Load()
        {
            using (IsolatedStorageFile Store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!Store.DirectoryExists("GameManager"))
                {
                    Store.CreateDirectory("GameManager");
                }

                string Path = "\\GameManager\\GameManager.xml";

                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(Path, FileMode.OpenOrCreate, Store))
                {
                    if (stream.Length > 0)
                    {
                        DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(GameManager));

                        try
                        {
                            GameManager gameManager = dataContractSerializer.ReadObject(stream) as GameManager;

                            return gameManager;
                        }
                        catch (Exception)
                        {
                            return null;
                        }
                    }
                    return null;
                }
            }
        }

        public static void Delete()
        {
            using (IsolatedStorageFile Store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!Store.DirectoryExists("GameManager"))
                {
                    return;
                }

                string Path = "\\GameManager\\GameManager.xml";

                if (Store.FileExists(Path))
                {
                    try
                    {
                        Store.DeleteFile(Path);
                    }
                    catch (Exception)
                    { }
                }
            }
        }

        public static bool IsExists()
        {
            using (IsolatedStorageFile Store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!Store.DirectoryExists("GameManager"))
                {
                    return false;
                }

                string Path = "\\GameManager\\GameManager.xml";

                if (Store.FileExists(Path))
                {
                    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(Path, FileMode.OpenOrCreate, Store))
                    {
                        if (stream.Length > 0)
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        }

        #endregion

        public static double ConvertX(double X)
        {
            return X;
        }

        public static double ConvertXBack(double X)
        {
            return X;
        }

        public static double ConvertY(double Y)
        {
            return TotalHeight - Y;
        }

        public static double ConvertYBack(double Y)
        {
            return TotalHeight - Y;
        }
    }

    public enum GameState
    {
        Play,
        Pause
    }
}
